﻿Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Namespace System.Workflow.ComponentModel.Design
    Friend NotInheritable Class ConnectionManager
        Inherits WorkflowDesignerMessageFilter
        Implements IDesignerGlyphProvider
        ' Methods
        Private Sub BeginEditing(ByVal editableConnector As ConnectorEditor, ByVal editPoint As Point)
            Dim parentView As WorkflowView = MyBase.ParentView
            If ((Not parentView Is Nothing) AndAlso (Not editableConnector Is Nothing)) Then
                Me.connectorEditor = editableConnector
                parentView.Capture = True
                Me.connectorEditor.OnBeginEditing(editPoint)
            End If
        End Sub

        Private Function CanBeginEditing(ByVal editPoint As Point, ByVal messageContext As HitTestInfo) As Boolean
            Dim service As ISelectionService = [TryCast](MyBase.GetService(GetType(ISelectionService)),ISelectionService)
            If (Not service Is Nothing) Then
                Dim connectorFromSelectedObject As Connector = Connector.GetConnectorFromSelectedObject(service.PrimarySelection)
                If (((Not connectorFromSelectedObject Is Nothing) AndAlso connectorFromSelectedObject.ParentDesigner.EnableUserDrawnConnectors) AndAlso New ConnectorEditor(connectorFromSelectedObject).HitTest(editPoint)) Then
                    Return True
                End If
            End If
            Dim info As ConnectionPointHitTestInfo = [TryCast](messageContext,ConnectionPointHitTestInfo)
            If ((Not info Is Nothing) AndAlso (Not info.ConnectionPoint Is Nothing)) Then
                Dim connectorContainer As FreeformActivityDesigner = ConnectionManager.GetConnectorContainer(info.AssociatedDesigner)
                If ((Not connectorContainer Is Nothing) AndAlso connectorContainer.EnableUserDrawnConnectors) Then
                    Return True
                End If
            End If
            Return False
        End Function

        Private Sub ContinueEditing(ByVal editPoint As Point)
            If Me.EditingInProgress Then
                Dim pointArray As ConnectionPoint() = Nothing
                If (Not Me.connectorEditor.EditedConectionPoint Is Nothing) Then
                    Dim sourceConnectionPoint As ConnectionPoint = If((Me.connectorEditor.EditedConnector.Source Is Me.connectorEditor.EditedConectionPoint), Me.connectorEditor.EditedConnector.Target, Me.connectorEditor.EditedConnector.Source)
                    pointArray = ConnectionManager.GetSnappableConnectionPoints(editPoint, sourceConnectionPoint, Me.connectorEditor.EditedConectionPoint, MyBase.MessageHitTestContext.AssociatedDesigner, Me.snappedConnectionPoint)
                End If
                Me.ConnectablePoints = pointArray
                If (Not Me.SnappedConnectionPoint Is Nothing) Then
                    editPoint = Me.SnappedConnectionPoint.Location
                End If
                Me.connectorEditor.OnContinueEditing(editPoint)
            End If
        End Sub

        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try 
                If disposing Then
                    Dim container As IServiceContainer = [TryCast](MyBase.GetService(GetType(IServiceContainer)),IServiceContainer)
                    If (Not container Is Nothing) Then
                        container.RemoveService(GetType(ConnectionManager))
                    End If
                    Dim service As IDesignerGlyphProviderService = [TryCast](MyBase.GetService(GetType(IDesignerGlyphProviderService)),IDesignerGlyphProviderService)
                    If (Not service Is Nothing) Then
                        service.RemoveGlyphProvider(Me)
                    End If
                End If
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub

        Private Sub EndEditing(ByVal editPoint As Nullable([Of] Point))
            Dim parentView As WorkflowView = MyBase.ParentView
            If (Not parentView Is Nothing) Then
                If Me.EditingInProgress Then
                    If editPoint.HasValue Then
                        If (Not Me.connectorEditor.EditedConectionPoint Is Nothing) Then
                            Dim sourceConnectionPoint As ConnectionPoint = If((Me.connectorEditor.EditedConnector.Source Is Me.connectorEditor.EditedConectionPoint), Me.connectorEditor.EditedConnector.Target, Me.connectorEditor.EditedConnector.Source)
                            ConnectionManager.GetSnappableConnectionPoints(editPoint.Value, sourceConnectionPoint, Me.connectorEditor.EditedConectionPoint, MyBase.MessageHitTestContext.AssociatedDesigner, Me.snappedConnectionPoint)
                        End If
                        If (Not Me.SnappedConnectionPoint Is Nothing) Then
                            editPoint = New Nullable([Of] Point)(Me.SnappedConnectionPoint.Location)
                        End If
                    End If
                    Me.connectorEditor.OnEndEditing(If(editPoint.HasValue, editPoint.Value, Point.Empty), editPoint.HasValue)
                End If
                Me.initialDragPoint = Nothing
                Me.dragPointHitInfo = Nothing
                Me.snappedConnectionPoint = Nothing
                Me.ConnectablePoints = Nothing
                parentView.Capture = False
                Me.connectorEditor = Nothing
            End If
        End Sub

        Friend Shared Function GetConnectorContainer(ByVal associatedDesigner As ActivityDesigner) As FreeformActivityDesigner
            Dim designer As FreeformActivityDesigner = Nothing
            If (Not associatedDesigner Is Nothing) Then
                Dim designer2 As ActivityDesigner = associatedDesigner
                Do While (Not designer2 Is Nothing)
                    If TypeOf designer2 Is FreeformActivityDesigner Then
                        designer = [TryCast](designer2,FreeformActivityDesigner)
                    ElseIf TypeOf designer2 Is InvokeWorkflowDesigner Then
                        Return designer
                    End If
                    designer2 = designer2.ParentDesigner
                Loop
            End If
            Return designer
        End Function

        Private Function GetConnectorEditor(ByVal editPoint As Point, ByVal messageContext As HitTestInfo) As ConnectorEditor
            Dim connectorEdited As Connector = Nothing
            Dim service As ISelectionService = [TryCast](MyBase.GetService(GetType(ISelectionService)),ISelectionService)
            If (Not service Is Nothing) Then
                Dim connectorFromSelectedObject As Connector = Connector.GetConnectorFromSelectedObject(service.PrimarySelection)
                If (((Not connectorFromSelectedObject Is Nothing) AndAlso connectorFromSelectedObject.ParentDesigner.EnableUserDrawnConnectors) AndAlso New ConnectorEditor(connectorFromSelectedObject).HitTest(editPoint)) Then
                    connectorEdited = connectorFromSelectedObject
                End If
            End If
            If (connectorEdited Is Nothing) Then
                Dim info As ConnectionPointHitTestInfo = [TryCast](messageContext,ConnectionPointHitTestInfo)
                If ((Not info Is Nothing) AndAlso (Not info.ConnectionPoint Is Nothing)) Then
                    Dim connectorContainer As FreeformActivityDesigner = ConnectionManager.GetConnectorContainer(info.AssociatedDesigner)
                    If ((Not connectorContainer Is Nothing) AndAlso connectorContainer.EnableUserDrawnConnectors) Then
                        connectorEdited = connectorContainer.CreateConnector(info.ConnectionPoint, info.ConnectionPoint)
                    End If
                End If
            End If
            If (connectorEdited Is Nothing) Then
                Return Nothing
            End If
            Return New ConnectorEditor(connectorEdited)
        End Function

        Private Shared Function GetHighlightableConnectionPoints(ByVal currentPoint As Point, ByVal activityDesigner As ActivityDesigner) As ConnectionPoint()
            Dim list As New List([Of] ConnectionPoint)
            Dim list2 As New List([Of] ActivityDesigner)
            Dim designer As FreeformActivityDesigner = [TryCast](activityDesigner,FreeformActivityDesigner)
            If (Not designer Is Nothing) Then
                list2.AddRange(designer.ContainedDesigners)
            End If
            list2.Add(activityDesigner)
            Dim designer2 As ActivityDesigner
            For Each designer2 In list2
                Dim flag As Boolean = designer2.Bounds.Contains(currentPoint)
                Dim connectionPoints As ReadOnlyCollection([Of] ConnectionPoint) = designer2.GetConnectionPoints(DesignerEdges.All)
                If Not flag Then
                    Dim point As ConnectionPoint
                    For Each point In connectionPoints
                        If point.Bounds.Contains(currentPoint) Then
                            flag = True
                            Exit For
                        End If
                    Next
                End If
                If flag Then
                    list.AddRange(connectionPoints)
                End If
            Next
            Return list.ToArray
        End Function

        Private Shared Function GetSnappableConnectionPoints(ByVal currentPoint As Point, ByVal sourceConnectionPoint As ConnectionPoint, ByVal activeConnectionPoint As ConnectionPoint, ByVal activityDesigner As ActivityDesigner, <Out> ByRef snappedConnectionPoint As ConnectionPoint) As ConnectionPoint()
            snappedConnectionPoint = Nothing
            Dim list As New List([Of] ConnectionPoint)
            Dim connectorContainer As FreeformActivityDesigner = ConnectionManager.GetConnectorContainer(activeConnectionPoint.AssociatedDesigner)
            If (Not connectorContainer Is Nothing) Then
                Dim designer2 As FreeformActivityDesigner = [TryCast](activityDesigner,FreeformActivityDesigner)
                Dim list2 As New List([Of] ActivityDesigner) { activityDesigner }
                If (Not designer2 Is Nothing) Then
                    list2.AddRange(designer2.ContainedDesigners)
                End If
                Dim num As Double = 20
                Dim designer3 As ActivityDesigner
                For Each designer3 In list2
                    If (ConnectionManager.GetConnectorContainer(designer3) Is connectorContainer) Then
                        Dim flag As Boolean = False
                        Dim collection As New List([Of] ConnectionPoint)
                        Dim point As ConnectionPoint
                        For Each point In designer3.GetConnectionPoints(DesignerEdges.All)
                            If (Not point.Equals(activeConnectionPoint) AndAlso connectorContainer.CanConnectContainedDesigners(sourceConnectionPoint, point)) Then
                                collection.Add(point)
                                Dim num2 As Double = DesignerGeometryHelper.DistanceFromPointToRectangle(currentPoint, point.Bounds)
                                If (num2 <= 20) Then
                                    flag = True
                                    If (num2 < num) Then
                                        snappedConnectionPoint = point
                                        num = num2
                                    End If
                                End If
                            End If
                        Next
                        If flag Then
                            list.AddRange(collection)
                        End If
                    End If
                Next
                If (Not snappedConnectionPoint Is Nothing) Then
                    Dim point2 As ConnectionPoint
                    For Each point2 In snappedConnectionPoint.AssociatedDesigner.GetConnectionPoints(DesignerEdges.All)
                        If Not list.Contains(point2) Then
                            list.Add(point2)
                        End If
                    Next
                End If
            End If
            Return list.ToArray
        End Function

        Protected Overrides Sub Initialize(ByVal parentView As WorkflowView)
            MyBase.Initialize(parentView)
            Dim container As IServiceContainer = [TryCast](MyBase.GetService(GetType(IServiceContainer)),IServiceContainer)
            If (Not container Is Nothing) Then
                container.RemoveService(GetType(ConnectionManager))
                container.AddService(GetType(ConnectionManager), Me)
            End If
            Dim service As IDesignerGlyphProviderService = [TryCast](MyBase.GetService(GetType(IDesignerGlyphProviderService)),IDesignerGlyphProviderService)
            If (Not service Is Nothing) Then
                service.AddGlyphProvider(Me)
            End If
        End Sub

        Protected Overrides Function OnKeyDown(ByVal eventArgs As KeyEventArgs) As Boolean
            If (Me.EditingInProgress AndAlso (eventArgs.KeyValue = &H1B)) Then
                Me.EndEditing(Nothing)
                eventArgs.Handled = True
            End If
            Return eventArgs.Handled
        End Function

        Protected Overrides Function OnMouseCaptureChanged() As Boolean
            Me.EndEditing(Nothing)
            Me.UpdateCursor(Nothing)
            Return False
        End Function

        Protected Overrides Function OnMouseDown(ByVal eventArgs As MouseEventArgs) As Boolean
            Dim empty As Point = Point.Empty
            If ((eventArgs.Button And MouseButtons.Left) = MouseButtons.Left) Then
                Dim parentView As WorkflowView = MyBase.ParentView
                Dim clientPoint As New Point(eventArgs.X, eventArgs.Y)
                If ((Not parentView Is Nothing) AndAlso parentView.IsClientPointInActiveLayout(clientPoint)) Then
                    Dim editPoint As Point = parentView.ClientPointToLogical(clientPoint)
                    If Me.CanBeginEditing(editPoint, MyBase.MessageHitTestContext) Then
                        Me.initialDragPoint = New Nullable([Of] Point)(editPoint)
                        Me.dragPointHitInfo = MyBase.MessageHitTestContext
                    End If
                    empty = editPoint
                End If
            Else
                Me.EndEditing(Nothing)
            End If
            Return (Me.initialDragPoint.HasValue Or Me.UpdateCursor(New Nullable([Of] Point)(empty)))
        End Function

        Protected Overrides Function OnMouseEnter(ByVal eventArgs As MouseEventArgs) As Boolean
            Dim empty As Point = Point.Empty
            Dim clientPoint As New Point(eventArgs.X, eventArgs.Y)
            Dim parentView As WorkflowView = MyBase.ParentView
            If (((Not parentView Is Nothing) AndAlso parentView.IsClientPointInActiveLayout(clientPoint)) AndAlso Not Me.EditingInProgress) Then
                Dim connectorContainer As FreeformActivityDesigner = ConnectionManager.GetConnectorContainer(MyBase.MessageHitTestContext.AssociatedDesigner)
                If ((Not connectorContainer Is Nothing) AndAlso connectorContainer.EnableUserDrawnConnectors) Then
                    Dim currentPoint As Point = parentView.ClientPointToLogical(clientPoint)
                    Me.ConnectablePoints = ConnectionManager.GetHighlightableConnectionPoints(currentPoint, MyBase.MessageHitTestContext.AssociatedDesigner)
                    empty = currentPoint
                End If
            End If
            Return Me.UpdateCursor(New Nullable([Of] Point)(empty))
        End Function

        Protected Overrides Function OnMouseLeave() As Boolean
            Me.EndEditing(Nothing)
            Me.UpdateCursor(Nothing)
            Return False
        End Function

        Protected Overrides Function OnMouseMove(ByVal eventArgs As MouseEventArgs) As Boolean
            Dim empty As Point = Point.Empty
            Dim parentView As WorkflowView = MyBase.ParentView
            Dim clientPoint As New Point(eventArgs.X, eventArgs.Y)
            If ((Not parentView Is Nothing) AndAlso parentView.IsClientPointInActiveLayout(clientPoint)) Then
                Dim editPoint As Point = parentView.ClientPointToLogical(clientPoint)
                If ((eventArgs.Button And MouseButtons.Left) = MouseButtons.Left) Then
                    If ((Not Me.EditingInProgress AndAlso Me.initialDragPoint.HasValue) AndAlso ((Math.Abs(CInt((Me.initialDragPoint.Value.X - editPoint.X))) > SystemInformation.DragSize.Width) OrElse (Math.Abs(CInt((Me.initialDragPoint.Value.Y - editPoint.Y))) > SystemInformation.DragSize.Height))) Then
                        Me.BeginEditing(Me.GetConnectorEditor(Me.initialDragPoint.Value, Me.dragPointHitInfo), Me.initialDragPoint.Value)
                    End If
                    If Me.EditingInProgress Then
                        Me.ContinueEditing(editPoint)
                        If (Not Me.SnappedConnectionPoint Is Nothing) Then
                            editPoint = Me.SnappedConnectionPoint.Location
                        End If
                    End If
                Else
                    Dim connectorContainer As FreeformActivityDesigner = ConnectionManager.GetConnectorContainer(MyBase.MessageHitTestContext.AssociatedDesigner)
                    Me.ConnectablePoints = If(((Not connectorContainer Is Nothing) AndAlso connectorContainer.EnableUserDrawnConnectors), ConnectionManager.GetHighlightableConnectionPoints(editPoint, MyBase.MessageHitTestContext.AssociatedDesigner), Nothing)
                End If
                empty = editPoint
            End If
            Return (Me.EditingInProgress Or Me.UpdateCursor(New Nullable([Of] Point)(empty)))
        End Function

        Protected Overrides Function OnMouseUp(ByVal eventArgs As MouseEventArgs) As Boolean
            Dim empty As Point = Point.Empty
            Dim editingInProgress As Boolean = Me.EditingInProgress
            If ((eventArgs.Button And MouseButtons.Left) = MouseButtons.Left) Then
                Dim parentView As WorkflowView = MyBase.ParentView
                Dim clientPoint As New Point(eventArgs.X, eventArgs.Y)
                If ((Not parentView Is Nothing) AndAlso parentView.IsClientPointInActiveLayout(clientPoint)) Then
                    Dim point3 As Point = parentView.ClientPointToLogical(clientPoint)
                    If Me.EditingInProgress Then
                        Me.EndEditing(New Nullable([Of] Point)(point3))
                    End If
                    empty = point3
                End If
            End If
            Me.EndEditing(Nothing)
            Return (editingInProgress Or Me.UpdateCursor(New Nullable([Of] Point)(empty)))
        End Function

        Protected Overrides Function OnPaint(ByVal e As PaintEventArgs, ByVal viewPort As Rectangle, ByVal ambientTheme As AmbientTheme) As Boolean
            Dim connectorEdited As Connector = Nothing
            Dim service As ISelectionService = [TryCast](MyBase.GetService(GetType(ISelectionService)),ISelectionService)
            Dim obj2 As Object
            For Each obj2 In service.GetSelectedComponents
                Dim connectorFromSelectedObject As Connector = Connector.GetConnectorFromSelectedObject(obj2)
                If (Not connectorFromSelectedObject Is Nothing) Then
                    connectorFromSelectedObject.OnPaintSelected(New ActivityDesignerPaintEventArgs(e.Graphics, connectorFromSelectedObject.ParentDesigner.Bounds, viewPort, connectorFromSelectedObject.ParentDesigner.DesignerTheme), (obj2 Is service.PrimarySelection), New Point(0  - 1) {})
                    If (obj2 Is service.PrimarySelection) Then
                        connectorEdited = connectorFromSelectedObject
                    End If
                End If
            Next
            If (Not connectorEdited Is Nothing) Then
                New ConnectorEditor(connectorEdited).OnPaint(New ActivityDesignerPaintEventArgs(e.Graphics, connectorEdited.ParentDesigner.Bounds, viewPort, connectorEdited.ParentDesigner.DesignerTheme), True, True)
            End If
            If Me.EditingInProgress Then
                Dim designer As FreeformActivityDesigner = If((Not Me.connectorEditor.EditedConnector.ParentDesigner Is Nothing), Me.connectorEditor.EditedConnector.ParentDesigner, ConnectionManager.GetConnectorContainer(Me.connectorEditor.EditedConnector.Source.AssociatedDesigner))
                Me.connectorEditor.OnPaint(New ActivityDesignerPaintEventArgs(e.Graphics, designer.Bounds, viewPort, designer.DesignerTheme), False, False)
            End If
            Return False
        End Function

        Private Function System.Workflow.ComponentModel.Design.IDesignerGlyphProvider.GetGlyphs(ByVal activityDesigner As ActivityDesigner) As ActivityDesignerGlyphCollection Implements IDesignerGlyphProvider.GetGlyphs
            Dim glyphs As New ActivityDesignerGlyphCollection
            Dim connectablePoints As ConnectionPoint() = Me.ConnectablePoints
            If (Not connectablePoints Is Nothing) Then
                Dim point As ConnectionPoint
                For Each point In connectablePoints
                    If (activityDesigner Is point.AssociatedDesigner) Then
                        glyphs.Add(New ConnectionPointGlyph(point))
                    End If
                Next
            End If
            Return glyphs
        End Function

        Private Function UpdateCursor(ByVal cursorPoint As Nullable([Of] Point)) As Boolean
            Dim snappedConnectionCursor As Cursor = Cursors.Default
            If cursorPoint.HasValue Then
                If Me.EditingInProgress Then
                    snappedConnectionCursor = Me.connectorEditor.GetCursor(cursorPoint.Value)
                End If
                If (Not Me.SnappedConnectionPoint Is Nothing) Then
                    snappedConnectionCursor = ConnectionManager.SnappedConnectionCursor
                ElseIf (Not Me.ConnectablePoints Is Nothing) Then
                    Dim point As ConnectionPoint
                    For Each point In Me.ConnectablePoints
                        If point.Bounds.Contains(cursorPoint.Value) Then
                            snappedConnectionCursor = ConnectionManager.SnappedConnectionCursor
                            Exit For
                        End If
                    Next
                    If (snappedConnectionCursor Is Cursors.Default) Then
                        Dim service As ISelectionService = [TryCast](MyBase.GetService(GetType(ISelectionService)),ISelectionService)
                        If (Not service Is Nothing) Then
                            Dim connectorFromSelectedObject As Connector = Connector.GetConnectorFromSelectedObject(service.PrimarySelection)
                            If ((Not connectorFromSelectedObject Is Nothing) AndAlso connectorFromSelectedObject.ParentDesigner.EnableUserDrawnConnectors) Then
                                snappedConnectionCursor = New ConnectorEditor(connectorFromSelectedObject).GetCursor(cursorPoint.Value)
                            End If
                        End If
                    End If
                End If
            End If
            Dim parentView As WorkflowView = MyBase.ParentView
            If ((Not parentView Is Nothing) AndAlso (((Not snappedConnectionCursor Is Cursors.Default) OrElse (parentView.Cursor Is ConnectionManager.SnappedConnectionCursor)) OrElse (parentView.Cursor Is ConnectionManager.NewConnectorCursor))) Then
                parentView.Cursor = snappedConnectionCursor
            End If
            Return (Not snappedConnectionCursor Is Cursors.Default)
        End Function


        ' Properties
        Private Property ConnectablePoints As ConnectionPoint()
            Get
                Return Me.connectablePoints
            End Get
            Set(ByVal value As ConnectionPoint())
                Dim parentView As WorkflowView = MyBase.ParentView
                If (Not parentView Is Nothing) Then
                    If (Not Me.connectablePoints Is Nothing) Then
                        Dim point As ConnectionPoint
                        For Each point In Me.connectablePoints
                            parentView.InvalidateLogicalRectangle(point.Bounds)
                        Next
                    End If
                    Me.connectablePoints = value
                    If (Not Me.connectablePoints Is Nothing) Then
                        Dim point2 As ConnectionPoint
                        For Each point2 In Me.connectablePoints
                            parentView.InvalidateLogicalRectangle(point2.Bounds)
                        Next
                    End If
                End If
            End Set
        End Property

        Private ReadOnly Property EditingInProgress As Boolean
            Get
                Return (Not Me.connectorEditor Is Nothing)
            End Get
        End Property

        Friend ReadOnly Property SnappedConnectionPoint As ConnectionPoint
            Get
                Return Me.snappedConnectionPoint
            End Get
        End Property


        ' Fields
        Private connectablePoints As ConnectionPoint()
        Private connectorEditor As ConnectorEditor
        Private dragPointHitInfo As HitTestInfo
        Private Const HighlightDistance As Integer = 20
        Private initialDragPoint As Nullable([Of] Point) = Nothing
        Friend Shared NewConnectorCursor As Cursor = New Cursor(GetType(WorkflowView), "Resources.ConnectorDraw.cur")
        Private Const SnapHighlightDistance As Integer = 20
        Friend Shared SnappedConnectionCursor As Cursor = New Cursor(GetType(WorkflowView), "Resources.Connector.cur")
        Private snappedConnectionPoint As ConnectionPoint
    End Class
End Namespace

